<?php

namespace Bete\Console;

use Exception;
use ReflectionMethod;
use Bete\Foundation\Application;
use Bete\Console\Route;
use Bete\Exception\ConsoleException;

class Core
{

    protected $app;

    protected $route;

    protected $bootstrappers = [
        'Bete\Bootstrap\LoadConfiguration',
        'Bete\Bootstrap\ConfigureLog',
        'Bete\Bootstrap\HandleException',
        'Bete\Bootstrap\RegisterConsoleProviders',
        'Bete\Bootstrap\BootProviders',
    ];

    public function __construct(Application $app, Route $route)
    {
        $this->app = $app;
        $this->route = $route;
    }

    public function bootstrap()
    {
        if (!$this->app->isBootstrapped()) {
            $this->app->bootstrapWith($this->bootstrappers());
        }
    }

    public function bootstrappers()
    {
        return $this->bootstrappers;
    }

    public function run()
    {
        $this->bootstrap();

        return $this->handle();
    }

    public function handle()
    {
        list($pathInfo, $params) = $this->route->resolve();

        return $this->runAction($pathInfo, $params);
    }

    public function runAction($pathInfo, $params = [])
    {
        $action = explode('/', $pathInfo);
        foreach ($action as $key => $value) {
            $action[$key] = ucfirst($value);
        }
        $class = 'App\\Console\\' . implode('\\', $action);

        try {
            $action = $this->app->make($class);
        } catch (\Exception $e) {
            throw new ConsoleException("Not Found");
        }

        $reflectionMethod = new ReflectionMethod('\\' . $class, 'run');

        $requiredNum = $reflectionMethod->getNumberOfRequiredParameters();

        if (count($params) < $requiredNum) {
            throw new ConsoleException("Missing required arguments.");
        }

        return $reflectionMethod->invokeArgs($action, $params);
    }

}
